/*
  The multiboot.c file handles the information structure passed by the multiboot compliant boot loader (ie GRUB)
*/

#include <globals.h>
#include <multiboot.h>

void parse_multi_boot_structure(void)
  {   
    struct Multiboot_Info_T *mbi;

    // examine multi boot structure

    // adjust structure pointer, depending on relocation
    GRUB_boot_header+=RELOC_PATCH/4;  // it's /4 because it's a dword_t pointer (4 Bytes long)

    mbi=(struct Multiboot_Info_T *)GRUB_boot_header;

    /*
    printf("FLAGS: %x\n",GRUB_boot_header[0]);    
    printf("Header at: %x\n",GRUB_boot_header);
    printf("Mem Lower: %x\n",GRUB_boot_header[1]);
    printf("Mem Upper: %x\n",GRUB_boot_header[2]); 
    */


    // Are mem_* valid? 
    if (CHECK_FLAG(mbi->flags,0))
      {
	mem_lower=mbi->mem_lower;
	mem_upper=mbi->mem_upper;

	// compute total amount of RAM in KBytes
	// (assume 1MB(= 1024 KB) is present)
	mem_tot=1024+mem_upper;	
      }

    // Is boot_device valid? 
    if (CHECK_FLAG(mbi->flags,1))
      {
	//printf ("boot_device = 0x%x\n", (unsigned) mbi->boot_device);
      }
    

    // Is the command line passed?
    if (CHECK_FLAG(mbi->flags,2))
      {
	//printf ("cmdline = %s\n", (char *) mbi->cmdline);
      }
    

    // Are mods_* valid? 
    if (CHECK_FLAG(mbi->flags,3))
      {
	struct ModulesList_T *mod;
	unsigned int i;
	
	//printf ("mods_count = %d, mods_addr = 0x%x\n",(int) mbi->mods_count, (int) mbi->mods_addr);
	mod = (struct ModulesList_T *) mbi->mods_addr;
	for (i = 0; i < mbi->mods_count; i++)
	  {
	  //printf (" mod_start = 0x%x, mod_end = 0x%x, string = %s\n",(unsigned) mod->mod_start,(unsigned) mod->mod_end,(char *) mod->string);
	    mod++;
	  }
      }


    // Are mmap_* valid?
    if (CHECK_FLAG(mbi->flags,6))
      {
	struct SysMemMap_T *mmap;
	unsigned long i;	
	qword_t curr_base,prev_base;
	qword_t bytes;
	dword_t kbytes;	

	//patch memory map address
	mbi->mmap_addr+=RELOC_PATCH;	
	
	// say that memory map is present
	mmap_valid=1;
	

	// compute total amount of RAM in KBytes
	// overwrite previous one, because this one is more accurate	
	curr_base=prev_base=0;
	for (i=0;i<mbi->mmap_length;i+=mmap->size+sizeof(mmap->size))
	  {
	    //calculate current entry
	    mmap=(struct SysMemMap_T *)((unsigned long)mbi->mmap_addr+i);	
	    
	    if (mmap->type==SMM_AVAILABLE)
	      {
		curr_base=(((qword_t)mmap->base_addr_high)<<32)+mmap->base_addr_low;

		if (curr_base>=prev_base)
		  {
		    kbytes=curr_base/1024;
		    bytes=(((qword_t)mmap->bytes_high)<<32)+mmap->bytes_low;
		    mem_tot=kbytes+bytes/1024;
		  }
		
		prev_base=curr_base;
	      }
	  }
      }
    else
      mmap_valid=0;  // memory map is not present

  }
